跳到主要内容

令人迷惑的写法

  • 下面的程序想要表达什么意思?

    template<class T>
    class Test {
    public:
    Test(T t) { }
    };

    template<class T>
    void func(T a[ ],int len) {

    }
  • 历史上的原因

    • 早期的C++直接复用class关键字来定义模板
    • 但是泛型编程针对的不只是类类型
    • class关键字的复用使得代码出现二义性
  • typename诞生的直接诱因

    • 自定义类类型内部的嵌套类型
    • 不同类中的同一个标识符可能导致二义性
    • 编译器无法辨识标识符究竟是什么?

编程实验

  • 模板中的二义性

    #include <iostream>
    #include <string>

    using namespace std;

    template < class T >
    class Test {
    public:
    Test(T t) {
    cout << "t = " << t << endl;
    }
    };

    template < class T >
    void func(T a[], int len) {
    for(int i=0; i<len; i++) {
    cout << a[i] << endl;
    }
    }


    //////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////

    int a = 0;

    class Test_1 {
    public:
    static const int TS = 1;
    };

    class Test_2 {
    public:
    struct TS {
    int value;
    };
    };

    template
    < class T >
    void test_class() {
    typename T::TS * a; // 1. 通过泛指类型 T 内部的数据类型 TS
    //定义指针变量 a (推荐的解读方式)
    // 2. 使用泛指类型 T 内部的静态成员变量 TS
    //与全局变量 a 进行乘法操作
    }


    int main(int argc, char *argv[]) {
    // test_class<Test_1>();
    test_class<Test_2>();
    return 0;
    }


令人迷惑的写法

typename的作用:

  1. 在模板定义中声明泛指类型
  2. 明确告诉编译器其后的标识符为类型
  • 下面的程序想要表达什么意思?

    int func(int i) try {
    return i;
    } catch(...) {
    return -1;
    }

    int func(int i,int j) throw(int) {
    return i+j;
    }
  • try...catch用于分隔正常功能代码与异常处理代码

  • try...catch可以直接将函数实现分隔为2部分

  • 函数声明和定义时可以直接指定可能抛出的异常类型

  • 异常声明成为函数的一部分可以提高代码可读性

  • 函数异常声明的注意事项

    • 函数异常声明是一种与编译器之间的契约
    • 函数声明异常后就只能抛出声明的异常
      • 抛出其它异常将导致程序运行终止
      • 可以直接通过异常声明定义无异常函数

编程实验

  • 新的异常算法

    #include <iostream>
    #include <string>

    using namespace std;

    int func(int i, int j) throw(int, char) {
    if( (0 < j) && (j < 10) ) {
    return (i + j);
    } else {
    throw '0';
    }
    }

    void test(int i) try {
    cout << "func(i, i) = " << func(i, i) << endl;
    } catch(int i) {
    cout << "Exception: " << i << endl;
    } catch(...) {
    cout << "Exception..." << endl;
    }


    int main(int argc, char *argv[]) {
    test(5);

    test(10);

    return 0;
    }

小结

  • class可以用来在模板中定义泛指类型(不推荐)
  • typename是可以消除模板中的二义性
  • try...catch可以将函数体分成2部分
  • 异常声明能够提供程序的可读性